#ifndef RASTER_H_
#define RASTER_H_

#include <stdio.h>
#include <vector>
#include <string>
#include <math.h>
#include <time.h>
#include <algorithm>
#include <Windows.h>
#include "st.h"
#include "gl/glu.h"
#include "gl/glut.h"
#include "gl/GL.h"
#pragma comment (lib, "Winmm.lib")

#define MIN(a,b)((a)<(b))?(a):(b)
#define MAX(a,b)((a)>(b))?(a):(b)

#define TESS_STEP 64								// this factor is used for models subdivided outside
#define MULTI_SAMPLE_RATE 64				// can be 1, 4, 16	
#define STAMP_SIZE 1								// can be 1, 4, 16, 64				
#define EPSILON 0.001
#define BACK_GROUND_COLOR STImage::Pixel(255,255,255) 
typedef bool bit;

// meta triangle analyze data
struct MetaData
{
	// STVector3 v0, v1, v2;
	int patch_id;							// belong to which patch
	float area;								// triangle area
	float hit_rate;						// hit rate without filter
	float hit_rate2;					// hit rate with filter
	float samples_bounded;			// samples covered per stamp
	float boundingbox_size;		// size of the bounding box 
	int num_filtered;					// Samples filtered in the bounding box
};

#define  ALPHA 250
#define  NUM_COLOR 9				// 

// initialized in class 
#define NUM_AREA 1

struct Area
{
	MetaData data;
	float area;
	int num;
};

class Raster
{
public:
	Raster(int w, int h);
	~Raster();

private:
	int width;
	int height;
	STImage *screen;
	STImage *screen2;				// for back patch
	int* analyze_buffer;		// to trace sampling times per pixel location.
	int* analyze_buffer2;		// to trace sampling times per pixel after optimization. 
	Area areas[NUM_AREA]; 
	STVector3 offset_pattern[MULTI_SAMPLE_RATE];
	STImage::Pixel color_list[NUM_COLOR];

	// projection matrix 
	GLdouble* m;
	GLint* v; 
	GLdouble* p;

	// samples per stamp
	int* stamps;
	STVector3* samples_per_stamp;

	// samples per bounding box
	STVector3* bound_samples;
	int boundbox_size;
	int num_bound_samples;
	std::vector<STVector3> filtered_samples;

	// bit masks per bounding box
	bit* bit_mask_buffer;
	bit* bound_bit_masks;
	bit* bit_masks_per_stamp;

	// raw data 
	int numIndices;
	int numPatches;
	GLfloat *vertices;
	GLfloat *normals;
	GLfloat *colors;
	GLuint *indices;
	GLuint *patches; 

	// analyze data
	std::vector<MetaData> data;
	std::vector<int> backfacingPatch;
	int P;		// number of all the sampling tests
	int P2;
	int a;		// number of fragments, cannot detect overlapped layer

	int nSub;
	int camPos;
	std::string model_name;

public:
	void init(GLfloat* v, GLfloat* n, GLfloat* c, GLuint* i, GLuint* p, int nv, int ni, int np);
	void raster(GLdouble* m, GLint* v, GLdouble* p);
	void raster2(GLdouble* m, GLint* v, GLdouble* p);		// for outside models already subdivided
	void generateGraph();
	void saveAnalyze();
	void saveGLScreen(char* name);
	void setSubN(int n){nSub = n;}
	void setCamPos(int n){camPos = n;}	// for different file names under different camera position
	void setName(char* name);
	void executionTime(GLdouble* m, GLint* v, GLdouble* p);		// only used for analysis execution time of each stage


private:
	void setup();
	void exeSetup(STVector3 &A, STVector3 &B, STVector3 &C);
	void exeBound(STVector3 &v0, STVector3 &v1, STVector3 &v2);
	void exeTest(STVector3 &A, STVector3 &B, STVector3 &C, STVector3 &P);


	bool facing(STVector3 &v0, STVector3 &v1, STVector3 &v2);
	void bound(STVector3 &v0, STVector3 &v1, STVector3 &v2);
	void rasterTriangle(int index, int pid);		// raster individual triangles, return false for back facing
	bool test(STVector3 &A, STVector3 &B, STVector3 &C, STVector3 &P);
	int filter();	// return new length

	STVector3* stampSamples(int x, int y);	// return the samples in the stamp
	bit* stampBitMasks(int x, int y);
	float triagnleArea(STVector3 &v0, STVector3 &v1, STVector3 &v2);
	STVector2 screenIndex(float x, float y);	// return the sample's pixel location
	void updateTest(int x, int y, int* buffer);	// update test to analyze buffer
	void updateBitMask(float x, float y);
	bool sampleInScreen(float x, float y);
	void clearAnalyzeBuffer();
	void clearBitMaskBuffer();
	void resetAnalyzeData();
	void initColor();
	void initSamples();
	void drawBackPatch();
};

#endif